package values

import (
	"math"

	"github.com/shopspring/decimal"
)

// RoundFloat64 四舍五入保留指定小数位数
func RoundFloat64(number float64, prec int) float64 {
	// 是否特殊浮点数（如NaN、正无穷、负无穷）则无法处理
	if math.IsNaN(number) || math.IsInf(number, 0) {
		return 0
	}
	if prec <= 0 {
		return math.Round(number)
	}
	x := math.Pow10(prec)
	return math.Round(number*x) / x
}

// RoundFloat32 四舍五入保留指定小数位数
//   - 32/64位的浮点数转换后精度丢失，使用shopspring/decimal库进行计算
func RoundFloat32(number float32, prec int) float32 {
	f64 := float64(number)
	// 是否特殊浮点数（如NaN、正无穷、负无穷）则无法处理
	if math.IsNaN(f64) || math.IsInf(f64, 0) {
		return 0
	}
	if prec <= 0 {
		return float32(decimal.NewFromFloat32(number).Round(0).InexactFloat64())
	}
	return float32(decimal.NewFromFloat32(number).Round(int32(prec)).InexactFloat64())
}

// FloorFloat64 向下取整保留指定小数位数（不四舍五入）
func FloorFloat64(number float64, prec int) float64 {
	// 是否特殊浮点数（如NaN、正无穷、负无穷）则无法处理
	if math.IsNaN(number) || math.IsInf(number, 0) {
		return 0
	}
	if prec <= 0 {
		return math.Floor(number)
	}
	x := math.Pow10(prec)
	return math.Floor(number*x) / x
}

// FloorFloat32 向下取整保留指定小数位数（不四舍五入）
//   - 32/64位的浮点数转换后精度丢失，使用shopspring/decimal库进行计算
func FloorFloat32(number float32, prec int) float32 {
	f64 := float64(number)
	// 是否特殊浮点数（如NaN、正无穷、负无穷）则无法处理
	if math.IsNaN(f64) || math.IsInf(f64, 0) {
		return 0
	}
	if prec <= 0 {
		return float32(decimal.NewFromFloat32(number).Floor().InexactFloat64())
	}
	return float32(decimal.NewFromFloat32(number).RoundDown(int32(prec)).InexactFloat64())
}

// CeilFloat64 向上取整保留指定小数位数（不四舍五入）
func CeilFloat64(number float64, prec int) float64 {
	// 是否特殊浮点数（如NaN、正无穷、负无穷）则无法处理
	if math.IsNaN(number) || math.IsInf(number, 0) {
		return 0
	}
	if prec <= 0 {
		return math.Ceil(number)
	}
	x := math.Pow10(prec)
	return math.Ceil(number*x) / x
}

// CeilFloat32 向上取整保留指定小数位数（不四舍五入）
//   - 32/64位的浮点数转换后精度丢失，使用shopspring/decimal库进行计算
func CeilFloat32(number float32, prec int) float32 {
	f64 := float64(number)
	// 是否特殊浮点数（如NaN、正无穷、负无穷）则无法处理
	if math.IsNaN(f64) || math.IsInf(f64, 0) {
		return 0
	}
	if prec <= 0 {
		return float32(decimal.NewFromFloat32(number).Ceil().InexactFloat64())
	}
	return float32(decimal.NewFromFloat32(number).RoundUp(int32(prec)).InexactFloat64())
}
